`include "mycpu.h"

module wb_stage(
    input                           clk           ,
    input                           reset         ,
    output                          flush         ,
    //allowin
    output                          ws_allowin    ,
    //from ms
    input                           ms_to_ws_valid,
    input  [`MS_TO_WS_BUS_WD -1:0]  ms_to_ws_bus  ,
    //from cp0
    input                   [31:0]  c0_rdata,
    //to rf: for write back
    output [`WS_TO_RF_BUS_WD -1:0]  ws_to_rf_bus  ,
    //to fs: for eret
    output [`WS_TO_FS_BUS_WD -1:0]  ws_to_fs_bus  ,
    //to cp0
    output [`WS_TO_CR_BUS_WD -1:0]  ws_to_cr_bus  ,
    //trace debug interface
    output [31:0] debug_wb_pc     ,
    output [ 3:0] debug_wb_rf_wen ,
    output [ 4:0] debug_wb_rf_wnum,
    output [31:0] debug_wb_rf_wdata,
    input  [5:0]  int,
    output op_tlbwi,
    output op_tlbr
);

reg         ws_valid;
wire        ws_ready_go;

reg [`MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus_r;
wire [ 3:0] ws_gr_we;
wire [ 4:0] ws_dest;
wire [31:0] ws_final_result;
wire [31:0] ws_pc;
wire ms_ex;
wire [4:0]ws_excode;
wire ws_ex;
wire ws_bd;
wire [4:0]ws_c0_waddr;
wire  [31:0] ws_badvaddr;
wire ws_inst_mfc0;
wire ws_inst_mtc0;
wire ws_inst_eret;
wire ws_tlb_r;

assign {ws_refetch,//123
        ws_tlb_r,//122
        op_tlbwi,//121
        op_tlbr,//120
        ws_badvaddr ,
        ws_c0_waddr ,
        ws_bd       ,
        ms_ex       ,
        ws_excode   ,
        ws_inst_mfc0,
        ws_inst_mtc0,
        ws_inst_eret,       //86:73
        ws_gr_we       ,  //72:69
        ws_dest        ,  //68:64
        ws_final_result,  //63:32
        ws_pc             //31:0
       } = ms_to_ws_bus_r;

wire [3 :0] rf_we;
wire [4 :0] rf_waddr;
wire [31:0] rf_wdata;
assign ws_to_rf_bus = {ws_inst_mfc0,//41:41
                       rf_we   ,  //40:37
                       rf_waddr,  //36:32
                       rf_wdata   //31:0
                      };

wire		[4:0]c0_addr;
wire		[31:0]c0_wdata;
wire		[5:0]ext_int_in;
/* cpu_top int signal, we need to change it in experiment after*/
assign      ext_int_in = int;

assign c0_addr  = ws_c0_waddr;
assign c0_wdata = ws_final_result;
assign ws_to_cr_bus={ws_badvaddr ,  //116:85
                    c0_addr,		//84:80
                    c0_wdata,		//79:48
                    ws_valid,
                    ws_ex & ~ws_refetch,
                    ws_bd,			//47:45
                    ws_excode,      //44:40
                    ws_pc,          //39:8
                    ws_inst_mtc0,
                    ws_inst_eret,   //7:6
                    ext_int_in      //5:0
                    };


wire eret;
assign eret = ws_inst_eret&&ws_valid;
assign ws_to_fs_bus={ws_refetch & ws_valid,//66
                    ws_pc,//65:34
                    ws_tlb_r&ws_valid,//33
                    eret,//32:1
                    c0_rdata};
//exception
assign ws_ex=ms_ex & ws_valid ;
assign flush =(ms_ex | ws_inst_eret) && ws_valid;

assign ws_ready_go = 1'b1;
assign ws_allowin  = !ws_valid || ws_ready_go;
always @(posedge clk) begin
    if (reset|flush) begin
        ws_valid <= 1'b0;
    end
    else if (ws_allowin) begin
        ws_valid <= ms_to_ws_valid;
    end

    if (ms_to_ws_valid && ws_allowin && ~flush) begin
        ms_to_ws_bus_r <= ms_to_ws_bus;
    end
end

assign rf_we    = ws_gr_we & {4{ws_valid}} & {4{~flush}} ;
assign rf_waddr = ws_dest;
assign rf_wdata = (ws_inst_mfc0)?c0_rdata:
                                ws_final_result;

// debug info generate
assign debug_wb_pc       = ws_pc;
assign debug_wb_rf_wen   = rf_we;
assign debug_wb_rf_wnum  = ws_dest;
assign debug_wb_rf_wdata = rf_wdata;

endmodule
